package com.xiaomaoguai.fcp.pre.kepler.glue.utils.extension;


import com.xiaomaoguai.fcp.pre.kepler.glue.exception.GlueException;
import com.xiaomaoguai.fcp.pre.kepler.glue.annotation.GlueSPI;

import java.util.Objects;
import java.util.ServiceLoader;
import java.util.stream.StreamSupport;


/**
 * The type Extension loader.
 *
 * @author xiaoyu
 */
public final class ExtensionLoader<T> {

    private Class<T> type;

    private ExtensionLoader(final Class<T> type) {
        this.type = type;
    }

    private static <T> boolean withExtensionAnnotation(final Class<T> type) {
        return type.isAnnotationPresent(GlueSPI.class);
    }

    /**
     * Gets extension loader.
     *
     * @param <T>  the type parameter
     * @param type the type
     * @return the extension loader
     */
    public static <T> ExtensionLoader<T> getExtensionLoader(final Class<T> type) {
        if (type == null) {
            throw new GlueException("type == null");
        }
        if (!type.isInterface()) {
            throw new GlueException("Extension type(" + type + ") not interface!");
        }
        if (!withExtensionAnnotation(type)) {
            throw new GlueException("type" + type.getName() + "not exist");
        }
        return new ExtensionLoader<>(type);
    }

    /**
     * Gets activate extension.
     *
     * @param value the value
     * @return the activate extension
     */
    public T getActivateExtension(final String value) {
        ServiceLoader<T> loader = ServiceBootstrap.loadAll(type);
        return StreamSupport.stream(loader.spliterator(), false)
                .filter(e -> Objects.equals(e.getClass()
                        .getAnnotation(GlueSPI.class).value(), value))
                .findFirst().orElseThrow(() -> new GlueException("Please check your configuration"));
    }

}
